#ifndef SCANLINE_RASTERIZER_MT_H_
#define SCANLINE_RASTERIZER_MT_H_

#include <Rasterizer.h>
#include <ScanlineRasterizer.h> //needed for Edge and Span

#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <QAtomicInt>


ATTRIBUTE_ALIGNED16(struct) EdgeData {
	Edge edges[3];
	int longEdge;
	int shortEdge1;
	int shortEdge2;
};

ATTRIBUTE_ALIGNED16(struct) TransformedFace {
	TransformedVertex	vertices[3];
	TransformedVertex	newVertices[3];
	
	int					numVertices; //3 or 6

	Fragment			fragments[3];
	Fragment			newFragment[3];

	Real				backface;
	Real				newBackface;
	EdgeData			edges;
	EdgeData			newEdges;
};

ATTRIBUTE_ALIGNED16(class) ScanLineRasterizerMT_VP_Thread : public QThread
{
public:
	ScanLineRasterizerMT_VP_Thread(QAtomicInt* working_threads, std::vector<TransformedFace>& tf) :	mWorkingThreads(working_threads), transformed_face_buffer(tf) {}

	QAtomicInt* mWorkingThreads;

	int start_idx;
	int end_idx;
	bool mAlive;

	QMutex mMutex;
	QWaitCondition mCondition;

	int wmi1, hmi1;//rt-width-1, rt-height-1
	
	std::vector<TransformedFace>&	transformed_face_buffer;
	const std::vector<Face>*		face_buffer;
		
	int						renderTargetWidth;
	int						renderTargetHeight;

	ShaderGlobals*			mShaderGlobals;
	VertexShaderParameters	mVShaderParams;
	VERTEXSHADER			mVertexShader;

	void init(int s, int e, const std::vector<Face>* fb, VERTEXSHADER shader, ShaderGlobals* glob);

	virtual void run();

	void transformTriangle(int face_idx);

	void rasterizeTriangle(TransformedVertex* vertices, EdgeData* edges, Real& a, Fragment* fragment);
private:
	Vec3 ndc[3];
	Vec4 v1diff, v2diff;
	Real varying1diff[MAX_VARYINGS], varying2diff[MAX_VARYINGS];
};


ATTRIBUTE_ALIGNED16(class) ScanLineRasterizerMT_FP_Thread : public QThread
{
public:
	ScanLineRasterizerMT_FP_Thread(QAtomicInt* working_threads, std::vector<TransformedFace>& tf) :	mWorkingThreads(working_threads), face_buffer(tf) {}

	QAtomicInt* mWorkingThreads;

	int ystart, yend;
	int ymod;
	int numThreads;
	bool mAlive;
	
	QMutex mMutex;
	QWaitCondition mCondition;

	ShaderGlobals*						mShaderGlobals;
	std::vector<TransformedFace>&		face_buffer;
	
	FragmentShaderParameters			mFShaderParams;
	FRAGMENTSHADER						mFragmentShader;

	void init(int ystart, int yend, int ymod, int numThreads, FRAGMENTSHADER shader, ShaderGlobals* glob);

	virtual void run();

	void drawSpanBetweenEdges(const Edge* longEdge, const Edge* shortEdge);
	void drawSpan(Span& span, const int y);
private:
	Fragment frag1, frag2;
	Span span;
	Fragment frag;
	Vec4 fragColor;
};

ATTRIBUTE_ALIGNED16(class) ScanLineRasterizerMT : public AbstractRasterizer
{
public:
	ScanLineRasterizerMT(int mRenderingThreads = 8);
	virtual ~ScanLineRasterizerMT();

protected:
	virtual void prepareForRender();
	virtual void renderMesh(const Mesh& mesh);

	
	std::vector<ScanLineRasterizerMT_VP_Thread*>	mVpThreads;
	std::vector<ScanLineRasterizerMT_FP_Thread*>	mFpThreads;
	int mRenderingThreads;
	QAtomicInt* working_threads;
	std::vector<TransformedFace> transformed_face_buffer;
};

#endif //SCANLINE_RASTERIZER_MT_H_